#include "cli.hpp"

#include "data.hpp"

#include <filesystem>
#include <iostream>
#include <memory>
#include <algorithm>
#include <cctype>

const std::filesystem::path current_dir = std::filesystem::current_path();
const std::filesystem::path GIT_DIR     = current_dir / ".mgit";
const std::filesystem::path OBJECT_DIR  = GIT_DIR / "objects";
const std::filesystem::path REFS_DIR    = GIT_DIR / "refs";
const std::filesystem::path TAGS_DIR    = REFS_DIR / "tags";
const std::filesystem::path HEADS_DIR   = GIT_DIR / "heads";
const std::filesystem::path HEAD        = GIT_DIR / "head";
const std::filesystem::path INDEX_FILE  = GIT_DIR / "index";

const std::string DEFAULT_PARENT_OID = "start_parent";

void trim(std::string &str);

std::unique_ptr<Command> parse_command(int argc, const char *argv[]) {
    // 检查是否提供了至少一个命令参数
    if (argc <= 1) {
        std::cerr << "错误: 必须至少提供一个命令参数。\n";
        std::cerr << "使用 --help 查看可用选项。\n";
        exit(EXIT_FAILURE);
    }
    std::unique_ptr<Command> command_ptr;
    std::string arg = argv[1];
    if (arg == "--help") {
        std::cout << "Usage: ./mygit [command] [args]\n\n";
        std::cout << "Available commands:\n";
        std::cout << "  --init         initialize a new repository\n";
        std::cout << "  --hash-object  compute object ID and optionally creates a "
                     "blob from a file\n";
        std::cout << "  --cat-file     output the contents of a repository object\n";
        std::cout << "  --write-tree   create a tree object from the current index\n";
        std::cout << "  --read-tree    read a tree object into the current index\n";
        std::cout << "  --commit       create a new commit object\n";
        std::cout << "  --help         display this help and exit\n";
        exit(EXIT_SUCCESS);
    } else if (arg == "--init") {
        command_ptr = std::make_unique<InitCommand>();
    } else if (arg == "--hash-object") {
        if (argc <= 2) {
            std::cerr << "错误: 必须提供一个文件路径。\n";
        } else {
            command_ptr = std::make_unique<HashObjectCommand>(current_dir / argv[2]);
        }
    } else if (arg == "--cat-file") {
        if (argc <= 2) {
            std::cerr << "错误: 必须提供一个对象 ID。\n";
        } else {
            command_ptr = std::make_unique<CatFileCommand>(OBJECT_DIR / argv[2]);
        }
    } else if (arg == "--write-tree") {
        command_ptr = std::make_unique<WriteTreeCommand>();
    } else if (arg == "--read-tree") {
        if (argc <= 2) {
            std::cerr << "错误: 必须提供一个树对象 ID。\n";
        } else {
            command_ptr = std::make_unique<ReadTreeCommand>(OBJECT_DIR / argv[2]);
        }
    } else if (arg == "--commit") {
        if (argc <= 2) {
            std::cerr << "错误: 必须提供一个提交信息。\n";
        } else {
            command_ptr = std::make_unique<CommitCommand>(argv[2]);
        }
    } else if (arg == "--log") {
        if (argc == 4) {
            command_ptr = std::make_unique<LogCommand>(argv[2]);
        } else {
            command_ptr = std::make_unique<LogCommand>();
        }

    } else if (arg == "--checkout") {
        if (argc <= 2) {
            std::cerr << "错误: 必须提供一个分支的oid。\n";
        } else {
            // 查找等号的位置
            std::string input = std::string(argv[2]);
            size_t equal_pos  = input.find('=');
            std::string left, right;
            if (equal_pos != std::string::npos) {
                // 将等号之前的部分作为左边字符串
                left = input.substr(0, equal_pos);
                // 将等号之后的部分作为右边字符串
                right = input.substr(equal_pos + 1);

                // 去除左边和右边的空格
                trim(left);
                trim(right);
            }
            if (left == "oid") {
                command_ptr = std::make_unique<CheckoutCommand>(CKECKOUT_OID, right);
            } else if (left == "tag") {
                command_ptr = std::make_unique<CheckoutCommand>(CKECKOUT_TAG, right);
            } else if (left == "branch") {
                command_ptr = std::make_unique<CheckoutCommand>(CKECKOUT_BRANCH, right);
            }
        }
    } else if (arg == "--tag") {
        if (argc <= 3) {
            std::cerr << "错误: 必须提供一个标签名和对应的uid。\n";
        } else {
            command_ptr = std::make_unique<TagCommand>(argv[2], argv[3]);
        }
    } else if (arg == "--branch") {
        if (argc <= 2) {
            std::cerr << "错误: 必须提供一个分支的名称。\n";
        } else {
            if (std::string(argv[2]) == "-a") {
                command_ptr = std::make_unique<BranchCommand>(BRANCH_LIST);
            } else {
                command_ptr = std::make_unique<BranchCommand>(BRANCH_CREATE, argv[2]);
            }
        }
    } else if (arg == "--status") {
        command_ptr = std::make_unique<StatusCommand>();
    } else if (arg == "--reset") {
        if (argc <= 2) {
            std::cerr << "错误: 必须提供一个oid。\n";
        } else {
            command_ptr = std::make_unique<ResetCommand>(argv[2]);
        }
    } else if (arg == "--show") {
        command_ptr = std::make_unique<ShowCommand>();
    } else if (arg == "--diff") {
        if (argc == 4) {
            command_ptr = std::make_unique<DiffCommand>(DIFF_STAGED);
        } else {
            command_ptr = std::make_unique<DiffCommand>(DIFF_HEAD);
        }

    } else if (arg == "--merge") {
        if (argc <= 2) {
            std::cerr << "错误: 必须提供一个分支的名称。\n";
        } else {
            command_ptr = std::make_unique<MergeCommand>(argv[2]);
        }
    } else if (arg == "--merge-base") {
        if (argc <= 3) {
            std::cerr << "错误: 必须提供两个对象branch名。\n";
        } else {
            command_ptr = std::make_unique<MergeBaseCommand>(argv[2], argv[3]);
        }
    } else if (arg == "--add") {
        if (argc <= 2) {
            std::cerr << "错误: 必须提供一个文件路径。\n";
        } else {
            command_ptr = std::make_unique<AddCommand>(argv[2]);
        }
    } else {
        // 如果没有匹配到任何命令，显示帮助信息
        std::cerr << "错误: 未识别的命令。\n";
        exit(EXIT_FAILURE);
    }

    return command_ptr;
}

void show_error_message(const ErrorMessage &error_message) {
    switch (error_message.code) {
    case ERROR_FILE_NOT_FOUND:
        std::cout << "File not found " << error_message.message << std::endl;
        break;
    case ERROR_FAILED_TO_GET_SHA1:
        std::cout << "Failed to get SHA1 of file " << error_message.message << std::endl;
        break;
    case ERROR_FAILED_TO_READ_FILE:
        std::cout << "Failed to read file " << error_message.message << std::endl;
        break;
    case ERROR_FILE_EXISTS:
        std::cout << "File already exists " << error_message.message << std::endl;
        break;
    case ERROR_INVALID_OBJECT_ID:
        std::cout << "Invalid object ID " << error_message.message << std::endl;
        break;
    case ERROR_FILE_WRITE_FAILED:
        std::cout << "Failed to write file " << error_message.message << std::endl;
        break;
    default:
        if (error_message.code != ERROR_OK) {
            std::cout << error_message.message << std::endl;
        }
        break;
    }
};

// 函数：去除字符串两端的空格
void trim(std::string &str) {
    // 去除左边空格
    str.erase(str.begin(), std::find_if(str.begin(), str.end(),
                                        [](unsigned char ch) { return !std::isspace(ch); }));

    // 去除右边空格
    str.erase(
        std::find_if(str.rbegin(), str.rend(), [](unsigned char ch) { return !std::isspace(ch); })
            .base(),
        str.end());
}
